﻿#include "anip.h"
#include "interface.h"
#include "audio/mixer.h"
#include "ui/native_dialogs.h"
#include <fstream>
//#include <iomanip>

#if defined(_MSC_VER)
#include "compatibility/dirent.h"
#else
#include <dirent.h>
#endif
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>

using namespace std;
using namespace anip;
using namespace anip::audio;

void sortGroup(SoundGroup& g)
{
	sort(g.sounds.begin(), g.sounds.end(), 
		[](Sound* a, Sound* b)
		{
			return a->name < b->name;
		});
}

Sound* readSoundFile(const string& path)
{
	Sound* s = Sound::create(path);
	if (s != nullptr && !s->readConfig())
		ui::native::messageBox(utf8s2ws(path) + L": config file corrupted");
	return s;
}

void readSounds()
{
	DIR* dir = nullptr, * dir2 = nullptr;
	struct dirent* entry = nullptr, * entry2 = nullptr;
	static struct stat info {};
	
	const string root{"./sounds"};
	
	if ((dir = opendir(root.c_str())) == nullptr)
		throw runtime_error("Directory unaccessible: "s + root);
		
	vector<string> mainGroupFiles, groupNames;
	vector<vector<string>> files;

	//ofstream temp("D:\\files.txt", ios::out);
	
	while ((entry = readdir(dir)) != nullptr)
	{
		if (entry->d_name[0] == '.') continue;
		string path(root);
		path.append("/");
		path.append(entry->d_name);
		if (stat(path.c_str(), &info) != 0) continue;
		
		if (S_ISDIR(info.st_mode))
		{
			// read sounds from subdirectories
			if ((dir2 = opendir(path.c_str())) == nullptr) continue;
			groupNames.push_back(entry->d_name);
			files.push_back(vector<string>{});
			while ((entry2 = readdir(dir2)) != nullptr)
			{
				string path2(path);
				path2.append("/");
				path2.append(entry2->d_name);
				//temp << path2 << endl;
				if (!fs::fileExists(path2) 
					|| fs::extension(path2) != ".ogg") continue;
				files.back().push_back(path2);
			}
			closedir(dir2);
		} else
		{
			//temp << path << endl;
			if (fs::extension(path) != ".ogg") continue;
			mainGroupFiles.push_back(path);
		}
	}

	//temp.close();
	
	closedir(dir);
	
	int count = mainGroupFiles.size();
	for (auto& i : files) count += i.size();
	int i = 0, j = 0;
	
	for (auto& path : mainGroupFiles)
	{
		while (i >= count * j / 100.0) { j++; cout << ":"; }
		i++;
		
		Sound* s = readSoundFile(path);
		if (s == nullptr) continue;
		MainGroup->sounds.push_back(s);
	}
	
	for (unsigned int k = 0; k < groupNames.size(); k++)
	{
		auto group = new SoundGroup(fs::path2ws(groupNames[k]));
		Groups.push_back(group);
		for (auto& path : files[k])
		{
			while (i >= count * j / 100.0) { j++; cout << ":"; }
			i++;
			
			Sound* s = readSoundFile(path);
			if (s == nullptr) continue;
			group->sounds.push_back(s);
		}
	}
	while (i >= count * j / 100.0) { j++; cout << ":"; }
	
	// sort
	sort(Groups.begin(), Groups.end(), 
		[](SoundGroup* a, SoundGroup* b) 
		{
			return a->name < b->name;
		});
	for (auto g : Groups)
		sortGroup(*g);
	sortGroup(*MainGroup);
	
	cout << endl << endl;
}

int main(int argc, char** argv)
{
	anip::init();
	Context::init({ 1200, 820 });
	Context::maxFramerate = 48;
	FontManager::addFace("std-latin", "C:\\Windows\\Fonts\\arial.ttf");
	FontManager::addFace("std-chn", "C:\\Windows\\Fonts\\simhei.ttf");
	FontManager::init();

	Mixer::init();
	auto devices = Mixer::devices();

	cout << "Reading sound files\n";
	readSounds();
	
	cout << "[[ SELECT OUTPUT DEVICE ]]\n\n";
	for (unsigned int i = 0; i < devices.size(); i++)
	{
		debug("%d: \t%dch [", i, devices[i].outChannels);
		debug(devices[i].name.c_str());
		debug(devices[i].defaultOutput ? "] (DEFAULT)\n" : "]\n");
	}
	
	cout << "\n>>> ";
	int select = 0;
	cin >> select;
	Mixer::begin(devices[select]);

	auto i = new Interface();
	i->mainLoop();

	delete i;

	Mixer::end();
	Mixer::finalize();
	FontManager::finalize();
	anip::finalize();
	return 0;
}